const { Board, utils } = require('board-game');
const extend = require('extend');
const VsCard = require('./card');

const { game: gameConfig } = require('./config');
const VsHome = require('./home');
const VsCardRole = require('./role');
const use = require('./use');

class VsCardBoard extends Board {
    constructor(game) {
        super(game);
        this.homes = game.groups.map(group => new VsHome(group));
        this.stage = gameConfig.stages.choose;
        this.tick = gameConfig.clocks.choose * this.chooseMulti;
        this.roles = this.groups.flatMap(group => group.roles);
        this.timer = setTimeout(() => this.step(), gameConfig.ticks[this.stage]);
        this.turn = false;
        this.round = 1;
        this.winIndex = -1;
        this.latest = false;
        this.history = [];
    }

    get chooseMulti() {
        if (this.game.room.settings.newHand) {
            return 3;
        } else {
            return 1;
        }
    }

    step() {
        if (this.winIndex !== -1) {
            this.game.over(this.winIndex);
            return;
        }
        if ((gameConfig.ticks[this.stage] * this.tick) % 1000 === 0) {
            for (let home of this.homes) {
                home.tick();
            }
        }
        if (this.stage === gameConfig.stages.choose) {
            this.tick--;
            if (this.tick <= 0) {
                for (let role of this.roles) {
                    if (!role.occupation) {
                        role.randomChoose();
                    }
                }
                this.tick = 0;
                this.stage = gameConfig.stages.first;
            } else if(this.roles.every(role => !!role.occupation)) {
                this.tick = 0;
                this.stage = gameConfig.stages.first;
            }
        } else if (this.stage === gameConfig.stages.first) {
            if (this.tick === 0) {
                let index = Math.floor(Math.random() * this.groups.length);
                let roles = [];
                while (this.roles.length) {
                    let preRoles = this.roles.filter(role => role.group === index);
                    let role = preRoles[Math.floor(preRoles.length * Math.random())];
                    let i = this.roles.indexOf(role);
                    roles.push(this.roles[i]);
                    this.roles.splice(i, 1);
                    index = (index + 1) % this.groups.length;
                }
                this.roles = roles;
                this.roles.forEach((role, index) => role.setIndex(index));
            }
            this.tick++;
            if (this.tick >= gameConfig.clocks.first) {
                this.tick = 0;
                if (this.round > 1) {
                    this.stage = gameConfig.stages.reissue;
                } else {
                    this.stage = gameConfig.stages.deal;
                }
            }
        } else if (this.stage === gameConfig.stages.reissue) {
            for (let role of this.roles) {
                role.addCard();
            }
            this.tick++;
            if (this.tick === gameConfig.card.reissueCount) {
                this.tick = gameConfig.clocks.replace * this.chooseMulti;
                this.stage = gameConfig.stages.replace;
            }
        } else if (this.stage === gameConfig.stages.deal) {
            for (let role of this.roles) {
                role.addCard();
            }
            this.tick++;
            if (this.tick === gameConfig.card.initCount) {
                this.tick = gameConfig.clocks.replace * this.chooseMulti;
                this.stage = gameConfig.stages.replace;
            }
        } else if (this.stage === gameConfig.stages.replace) {
            this.tick--;
            if (this.tick <= 0) {
                this.tick = gameConfig.clocks.turn * this.chooseMulti;
                this.stage = gameConfig.stages.play;
                this.turn = 0;
                this.roles[this.turn].doPlay();
            } else if (this.roles.every(role => role.replace >= gameConfig.card.replaceCount)) {
                this.tick = gameConfig.clocks.turn * this.chooseMulti;
                this.stage = gameConfig.stages.play;
                this.turn = 0;
                this.roles[this.turn].doPlay();
            }
        } else if (this.stage === gameConfig.stages.use) {
            this.tick++;
            if (this.use && this.tick >= gameConfig.clocks.use) {
                let result = this.use.card.use(this, this.use.role.group, this.use.role, this.use.role.ownHome, 
                    this.use.targets.map(target => {
                        if (target.type === 'ownGroup') {
                            return this.use.role.ownGroup;
                        } else if (target.type === 'targetGroup') {
                            return this.use.role.targetGroup;
                        } else {
                            return false;
                        }
                    }).filter(group => !!group), 
                    this.use.targets.map(target => {
                        if (target.type === 'ownRole') {
                            return this.use.role;
                        } else if (target.type === 'targetRole') {
                            return this.use.targetGroup.role[target.index];
                        } else {
                            return false;
                        }
                    }).filter(group => !!group), 
                    this.use.targets.map(target => {
                        if (target.type === 'ownHome') {
                            return this.use.role.ownHome;
                        } else if (target.type === 'targetHome') {
                            return this.use.role.targetHome;
                        } else {
                            return false;
                        }
                    }).filter(group => !!group));
                if (!result || !result.pile) {
                    this.use.role.doFold(this.use.card);
                }
                this.use.role.latest = use.asRoleResult(this.use, result);
                this.latest = use.asResult(this.use, result);
                this.history.push(use.asData(this.latest));
                this.use = false;
                this.tick = 0;
            } else if (!this.use && this.tick >= this.latest.card.option.tick + gameConfig.clocks.use) {
                this.latest = false;
                this.nextTurn();
            }
        } else if (this.stage === gameConfig.stages.play) {
            if (this.tick > 0) {
                this.tick--;
            } else {
                if (this.roles[this.turn].isPlay()) {
                    this.roles[this.turn].doPass();
                }
            }
        } else {
            if (this.stage === gameConfig.stages.wait) {
                this.stage = gameConfig.stages.clear;
            }
            if (this.stage === gameConfig.stages.clear) {
                if (this.homes.some(home => home.troops.some(soldier => soldier.hasBuff())) || this.homes.some(home => home.reinforces.length)) {
                    this.tick++;
                    if (this.tick >= gameConfig.clocks.clear) {
                        for (let home of this.homes) {
                            home.clearBuff();
                        }
                        this.tick = 0;
                        this.stage = gameConfig.stages.random;
                    }
                } else {
                    this.tick = 0;
                    this.stage = gameConfig.stages.random;
                }
            }
            if (this.stage === gameConfig.stages.random) {
                let maxValue = this.homes.reduce((max, home) => Math.max(max, home.troops.length), 0);
                if (this.homes.filter(home => home.troops.length === maxValue).length > 1) {
                    //平局猜拳
                    this.tick++;
                    if (this.tick >= gameConfig.clocks.random) {
                        this.homes[Math.floor(this.homes.length * Math.random())].doHelp();
                        this.tick = 0;
                        this.stage = gameConfig.stages.settle;
                    }
                } else {
                    this.tick = 0;
                    this.stage = gameConfig.stages.settle;
                }
            }
            if (this.stage === gameConfig.stages.settle) {
                this.tick++;
                if (this.tick >= gameConfig.clocks.settle) {
                    let maxValue = this.homes.reduce((max, home) => Math.max(max, home.troops.length), 0);
                    let winHome = this.homes.find(home => home.troops.length === maxValue);
                    winHome.winCount++;
                    if (winHome.winCount > this.room.settings.round / 2) {
                        //结束
                        for (let role of this.roles) {
                            role.clear();
                        }
                        this.game.clear();
                        this.winIndex = winHome.group.index;
                    } else {
                        //下一轮次开始
                        this.round++;
                        for (let home of this.homes) {
                            home.reset();
                        }
                        for (let role of this.roles) {
                            role.doWait();
                        }

                        //重新猜先
                        let index = winHome.group.index;
                        let roles = [];
                        while (this.roles.length) {
                            let preRoles = this.roles.filter(role => role.group === index);
                            let role = preRoles[Math.floor(preRoles.length * Math.random())];
                            let i = this.roles.indexOf(role);
                            roles.push(this.roles[i]);
                            this.roles.splice(i, 1);
                            index = (index + 1) % this.groups.length;
                        }
                        this.roles = roles;
                        this.roles.forEach((role, index) => role.setIndex(index));

                        this.tick = 1;
                        this.stage = gameConfig.stages.first;
                    }
                }
            }
        }
        this.timer = setTimeout(() => this.step(), gameConfig.ticks[this.stage]);
    }

    useCard(role, card, targets) {
        this.use = use.asUse(card, targets, role);
        this.tick = 0;
        this.stage = gameConfig.stages.use;
    }

    nextTurn() {
        this.tick = gameConfig.clocks.turn * this.chooseMulti;
        this.turn++;
        if (this.roles.every(role => role.isPass())) {
            this.tick = 0;
            this.stage = gameConfig.stages.wait;
        } else {
            if (this.turn >= this.roles.length) {
                this.turn = 0;
            }
            this.roles[this.turn].doPlay();
            this.stage = gameConfig.stages.play;
            for (let home of this.homes) {
                home.checkStart(this.roles[this.turn]);
            }
        }
    }

    get data() {
        return extend(true, super.data, {
            tick: this.tick,
            stage: this.stage,
            homes: this.homes.map(home => home.data),
            round: this.round,
            turn: this.turn,
            role: this.stage === gameConfig.stages.play ? this.roles[this.turn].summary : false,
            roles: this.roles.map(role => role.summary),
            occupations: VsCardRole.occupations.map(o => ({
                type: o.type,
                name: o.name,
                desc: o.desc
            })),
            use: use.asData(this.use),
            latest: use.asData(this.latest),
            history: utils.asObject(this.history),
        });
    }
}

module.exports = VsCardBoard;